// SyncQueue.h: interface for the SyncQueue class.
//
//////////////////////////////////////////////////////////////////////

#ifndef SYNCQUEUE_H
#define SYNCQUEUE_H

#include "lockfree.h"
#include <atomic>
#include <condition_variable>
#include <chrono>
#include <list>
#include "common.h"


template<class E>
class SyncQueue
{
public:
    SyncQueue()
    {
        m_buffer.clear();
    }

    ~SyncQueue()
    {

    }
    
    int GetSize()
    {
        std::unique_lock<std::mutex> unique_lock(m_mutex);
        return m_buffer.size();
    }

    void Append(E& e)
    {
        //LOGFMTW("Append data1");
         bool iswake = false;
        {
            m_mutex.lock();
            iswake = m_buffer.empty();
            m_buffer.push_back(e);
            m_mutex.unlock();
        }
        
        if (iswake){
            //LOGFMTW("send notify1");
            m_condition.notify_one();
        } 
    }

    void Append(E&& e)
    {
        //LOGFMTW("Append data");
        bool iswake = false;
        {
            m_mutex.lock();
            iswake = m_buffer.empty();
            //iswake = (m_freeThreadCount > 0);
            m_buffer.push_back(std::move(e));
            m_mutex.unlock();
        }

        if (iswake){
            //LOGFMTW("send notify");
             m_condition.notify_one();
        }
    }

    bool RemoveHead(E& pe, uint seconds_timeout)
    {
        std::unique_lock<std::mutex> unique_lock(m_mutex);
        if (m_buffer.empty())
        {
            // LOGFMTW("thread sleep");
            //std::unique_lock<std::mutex> unique_lock(m_mutex);
            auto now = std::chrono::system_clock::now();
            if (m_condition.wait_until(unique_lock, now + std::chrono::duration<int, std::milli>(seconds_timeout * 1000)) == std::cv_status::timeout) return false;
            if(m_buffer.empty()){
                return false;
            }
            //LOGFMTW("thread wakeup");
        }
        
        pe = m_buffer.front();
        m_buffer.pop_front();
        return true;
    }

private:

    std::condition_variable m_condition;
    std::mutex m_mutex;
    //lockfree::queue<E> m_buffer;
    std::list<E>         m_buffer;
};

#endif
